
package com.ikas.ai.utils;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author HXH
 * @version V1.0
 * @Title: HttpUtil
 * @Package com.ikas.utils
 * @Description: Http请求工具类
 * @date 2021年6月21日
 */
public class HttpUtil {

    private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
    // 建立连接超时时间
    private static int connectTimeout = 5000;
    // 建立连接超时时间
    private static int connectRequestTimeout = 5000;
    // 设置等待数据超时时间5秒钟 根据业务调整
    private static int socketTimeout = 5000;
    // 连接池最大连接数
    private static int maxTotal = 8;
    // 每个主机的并发
    private static int maxPerRoute = 10;
    // 设置重试次数
    private static int maxRetry = 0;

    // 设置连接池管理
    private static PoolingHttpClientConnectionManager poolConnManager = null;
    private static CloseableHttpClient httpClient = null;
    //响应处理器
    private static ResponseHandler<String> responseHandler = null;

    static {
        try {
            SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
            // 配置同时支持 HTTP 和 HTPPS
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
            // 初始化连接管理器
            poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            poolConnManager.setMaxTotal(maxTotal);// 同时最多连接数
            // 设置最大路由
            poolConnManager.setDefaultMaxPerRoute(maxPerRoute);
            // 初始化httpClient
            httpClient = getConnection();

            // 初始化response解析器保证释放连接
            responseHandler = new BasicResponseHandler();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
    }

    public static CloseableHttpClient getConnection() {
        RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectRequestTimeout).setSocketTimeout(socketTimeout).build();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(poolConnManager)
                .setDefaultRequestConfig(config)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(maxRetry, false)).build();
        return httpClient;
    }

    public static CloseableHttpResponse send(HttpUriRequest request) throws Exception {
        CloseableHttpResponse response = httpClient.execute(request);
        response.close();
        return response;
    }

    /**
     * @param @param  url 请求地址
     * @param @return
     * @param @throws IOException    参数
     * @return String    返回类型
     * @throws
     * @Title: sendGet
     * @Description: 发送HttpGet请求
     * @author HXH
     */
    public static String sendGet(String url) {
        return sendGet(url, null);
    }

    /**
     * @param @param  url 请求地址
     * @param @param  headers 请求头部
     * @param @return 参数
     * @return String    返回类型
     * @throws
     * @Title: sendGet
     * @Description: 发送HttpGet请求
     * @author HXH
     */
    public static String sendGet(String url, Map<String, String> headers) {
        String response = null;
        try {
            HttpGet get = new HttpGet(url);
            if (headers != null) {
                headers.forEach((k, v) -> get.addHeader(k, v));
            }
            response = httpClient.execute(get, responseHandler);
        } catch (Exception e) {
            logger.error(String.format("HttpUtil sendGet throw new exception! url: %s", url), e);
        }
        return response;
    }

    /**
     * @param @param  url 请求地址
     * @param @return
     * @param @throws IOException    参数
     * @return String    返回类型
     * @throws
     * @Title: sendPost
     * @Description: 发送HttpPost请求
     * @author HXH
     */
    public static String sendPost(String url) {
        return sendPost(url, null, null, null);
    }

    /**
     * @param @param  url 请求地址
     * @param @param  body 请求消息体
     * @param @return
     * @param @throws IOException    参数
     * @return String    返回类型
     * @throws
     * @Title: sendPost
     * @Description: 发送HttpPost请求
     * @author HXH
     */
    public static String sendPost(String url, HttpEntity body) {
        return sendPost(url, body, null, null);
    }

    /**
     * @param @param  url 请求地址
     * @param @param  params 请求参数
     * @param @return 参数
     * @return String    返回类型
     * @throws
     * @Title: sendPost
     * @Description: 发送HttpPost请求
     * @author HXH
     */
    public static String sendPost(String url, Map<String, Object> params) {
        return sendPost(url, null, params, null);
    }

    /**
     * @param @param  url 请求地址
     * @param @param  body 请求消息体
     * @param @param  header 请求头部信息
     * @param @return
     * @param @throws IOException    参数
     * @return String    返回类型
     * @throws
     * @Title: sendPost
     * @Description: 发送HttpPost请求
     * @author HXH
     */
    public static String sendPost(String url, HttpEntity body, Map<String, String> headers) {
        return sendPost(url, body, null, headers);
    }

    /**
     * @param @param  url 请求地址
     * @param @param  body 请求消息体
     * @param @param  params 请求参数
     * @param @param  header 请求头部信息
     * @param @return
     * @param @throws IOException    参数
     * @return String    返回类型
     * @throws
     * @Title: sendPost
     * @Description: 发送HttpPost请求
     * @author HXH
     */
    public static String sendPost(String url, HttpEntity body, Map<String, Object> params, Map<String, String> headers) {
        String response = null;
        try {
            HttpPost post = new HttpPost(url);
            if (headers != null) {
                headers.forEach((k, v) -> post.addHeader(k, v));
            }
            if (null != body) {
                post.setEntity(body);
            }
            if (null != params) {
                setPostParams(post, params);
            }
            response = httpClient.execute(post, responseHandler);
        } catch (Exception e) {
            logger.error(String.format("HttpUtil sendPost throw new exception! url: %s", url), e);
        }
        return response;
    }

    public static void setPostParams(HttpPost httpost, Map<String, Object> params) {
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
        }
        try {
            httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        } catch (Exception e) {
            logger.error(String.format("HttpUtil setPostParams throw new exception! url: %s", httpost.getURI()), e);
        }
    }
}